package com.kingdee.eas.patch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * zip补丁包的工具类
 * Created by Niki on 2018/5/15 11:58
 */
public class ZipUtil {
    private static final Logger logger = LoggerFactory.getLogger(ZipUtil.class);
    /**
     * 解压文件
     * class文件
     * @param patch
     */
    public static Map<String, String> decompressZip(String patch) throws PatchException {
        //记录补丁类全名称对应class文件绝对路径的map

        File file = new File(patch);
//        if (!isZIP(file)) {
//            return;
//        }

        String tmpDir = Constant.tmpDir;
        File $tmpDir = new File(tmpDir);
        if (!$tmpDir.exists()) {
            $tmpDir.mkdirs();
        }

        ZipFile zipFile = null;
        Properties properties = new Properties();
        try {
            zipFile = new ZipFile(file);

        } catch (IOException e) {
            logger.error("加载：{}路径下的zip文件异常！",patch, e);
            throw new PatchException("加载" + patch + "路径下的zip文件异常！");
        }

       judgeUpdate(tmpDir, zipFile, properties);

        Map<String, String> map = new HashMap<>(zipFile.size());
        Enumeration<ZipEntry> zipEntrys = (Enumeration<ZipEntry>) zipFile.entries();
        ZipEntry zipEntry;
        while (zipEntrys.hasMoreElements()) {
            zipEntry = zipEntrys.nextElement();
            String zipName = zipEntry.getName();
            String filePath = Constant.tmpDir + File.separator + zipName;
            File tmpFile = new File(filePath);
            //zip包里的文件时目录的情况
            if (zipEntry.isDirectory()) {
                if (!tmpFile.exists()) {
                    tmpFile.mkdirs();
                }
                continue;
            }

            if (tmpFile.exists()) {
                tmpFile.delete();
            }
            try {
                tmpFile.createNewFile();
            } catch (IOException e) {
                logger.error("解压补丁中文件：{} 到路径：{} 下发生异常！",zipName, filePath,e);
                throw new PatchException("解压补丁中文件：" + zipName + "异常！");
            }
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                inputStream = zipFile.getInputStream(zipEntry);
                outputStream = new FileOutputStream(tmpFile);
                IOUtils.copyLarge(inputStream, outputStream);
                map.put(properties.getProperty(tmpFile.getName()), tmpFile.getAbsolutePath());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                IOUtils.closeQuietly(outputStream);
                IOUtils.closeQuietly(inputStream);
            }
        }
        return map ;
    }

    /**
     * 解压zip文件，war包形式
     * @param path zip包下载的地址
     * @return 返回war包的地址
     */
    public static String decompressZip_war(String path) throws PatchException {
        String warPath = "";
        File file = new File(path);
        String tmpDir = Constant.tmpDir;
        File $tmpDir = new File(tmpDir);
        if (!$tmpDir.exists()) {
            $tmpDir.mkdirs();
        }
        ZipFile zipFile = null;
        Properties properties = new Properties();
        try {
            zipFile = new ZipFile(file);

        } catch (IOException e) {
            logger.error("加载：{}路径下的zip文件异常！",path, e);
            throw new PatchException("加载" + path + "路径下的zip文件异常！");
        }
        judgeUpdate(tmpDir, zipFile, properties);
        Enumeration<ZipEntry> zipEntrys = (Enumeration<ZipEntry>) zipFile.entries();
        ZipEntry zipEntry ;
        while (zipEntrys.hasMoreElements()) {
            zipEntry = zipEntrys.nextElement();
            String zipName = zipEntry.getName();
            String filePath = Constant.tmpDir + File.separator + zipName;
            File tmpFile = new File(filePath);
            //zip包里的文件时目录的情况
            if (zipEntry.isDirectory()) {
                if (!tmpFile.exists()) {
                    tmpFile.mkdirs();
                }
                continue;
            }

            if (tmpFile.exists()) {
                tmpFile.delete();
            }
            if (zipName.endsWith(".war")) {
                warPath = tmpFile.getAbsolutePath();
            }
            try {
                tmpFile.createNewFile();
            } catch (IOException e) {
                logger.error("解压补丁中文件：{} 到路径：{} 下发生异常！",zipName, filePath,e);
                throw new PatchException("解压补丁中文件：" + zipName + "异常！");
            }
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                inputStream = zipFile.getInputStream(zipEntry);
                outputStream = new FileOutputStream(tmpFile);
                IOUtils.copyLarge(inputStream, outputStream);

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                IOUtils.closeQuietly(outputStream);
                IOUtils.closeQuietly(inputStream);
            }
        }
        return warPath;
    }

    /**
     * 判断文件是否为zip文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    private static boolean isZIP(File file) throws IOException {
        InputStream inputStream = new FileInputStream(file);
        byte[] head = new byte[4];
        if (-1 == inputStream.read(head)) {
            return false;
        }
        inputStream.close();
        int headHex = 0;
        for (byte b : head) {
            headHex <<= 8;
            headHex |= b;
        }
        switch (headHex) {
            case 0x504B0304:
                return true;
            default:
                return false;
        }
    }

    /**
     * 判断是否可以更新补丁
     *
     * @param tmpDir
     * @param zipFile
     * @return
     * @throws IOException
     */
    private static boolean judgeUpdate(String tmpDir, ZipFile zipFile, Properties properties) throws PatchException {
        Enumeration<ZipEntry> zipEntrys = (Enumeration<ZipEntry>) zipFile.entries();
        while (zipEntrys.hasMoreElements()) {
            ZipEntry zipEntry = zipEntrys.nextElement();
            String name = zipEntry.getName();
            if (name.contains(Constant.PROPERTIES_NAME)) {
                String path = tmpDir + File.separator + name;
                //该文件为配置文件
                File file = new File(tmpDir + File.separator + name);

                if (file.exists()) {
                    //存在之前的配置文件，判断该补丁有效
                    Properties oldProperties = getProperties(path);

                    try {
                        properties.load(zipFile.getInputStream(zipEntry));
                    } catch (IOException e) {
                        logger.error("查询补丁配置文件异常", e);
                        throw new PatchException("查询补丁配置文件异常");
                    }

                    String oldVersion = oldProperties.getProperty("version");
                    String newVersion = properties.getProperty("version");
                    if (oldVersion.equals(newVersion)) {
                        logger.info("新补丁版本：{}与老版本补丁：{}一致，不更新该补丁！", newVersion, oldVersion);
                        throw new PatchException("新补丁版本："+newVersion+"与老版本补丁："+oldVersion+"一致，不更新该补丁！");
                    }
                }
            }
        }
        return true;
    }

    private static Properties getProperties(String path) throws PatchException {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream(path));
            properties.getProperty("version");
        } catch (IOException e) {
            logger.error("查询旧版配置文件异常", e);
            throw new PatchException("查询旧版补丁配置文件异常");
        }
        return properties;
    }

}
